/**
 * 
 */
package com.xpec.c4.message;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.utility.GameUtility;

/**
 * 
 * @author TW15010
 * 
 */
public class ConstantCode {
	/** log4j object */
	private static final Log log = LogFactory.getLog(ConstantCode.class);

	/**
	 * 記錄指定 class 底下的 int field<br>
	 * classMap [class, constMap]<br>
	 * constMap [field value, field]
	 */
	private static HashMap<Class<?>, HashMap<Integer, Field>> classMap = new HashMap<Class<?>, HashMap<Integer, Field>>();

	/**
	 * 指定的 constant value 是否存在
	 * 
	 * @param c
	 *            屬於哪個 class
	 * @param constValue
	 *            數值
	 * @return true: 存在<br>
	 *         false: 不存在
	 */
	public static boolean isValid(Class<?> c, int constValue) {
		HashMap<Integer, Field> constMap = getConstantCodeMap(c);

		boolean isExist = constMap.containsKey(constValue);

		return isExist;
	}

	/**
	 * 取得指定數值對應的 constant 變數名稱
	 * 
	 * @param c
	 *            屬於哪個 class
	 * @param constValue
	 *            數值
	 * @return 變數名稱
	 */
	public static String getName(Class<?> c, int constValue) {
		HashMap<Integer, Field> constMap = getConstantCodeMap(c);

		// 找出數值對應的 field
		Field field = constMap.get(constValue);
		if (field == null) {
			return "null";
		}

		return field.getName();
	}

	/**
	 * 取得指定數值對應的 constant 變數名稱
	 * 
	 * @param c
	 *            屬於哪個 class
	 * @param constValue
	 *            數值
	 * @return 變數名稱 ex: INVALIT_PARAM(12345)
	 */
	public static String getNameWithCode(Class<?> c, int constValue) {
		HashMap<Integer, Field> constMap = getConstantCodeMap(c);

		// 找出數值對應的 field
		Field field = constMap.get(constValue);
		if (field == null) {
			return "null";
		}

		return field.getName() + "(" + constValue + ")";
	}

	/**
	 * 取得指定數值對應的完整 constant 變數名稱
	 * 
	 * @param c
	 *            屬於哪個 class
	 * @param constValue
	 *            數值
	 * @return 變數名稱 ex: ErrorCode.INVALIT_PARAM
	 */
	public static String getFullName(Class<?> c, int constValue) {
		HashMap<Integer, Field> constMap = getConstantCodeMap(c);

		// 找出數值對應的 field
		Field field = constMap.get(constValue);
		if (field == null) {
			return "null";
		}

		return c.getSimpleName() + "." + field.getName();
	}

	/**
	 * 取得指定數值對應的完整 constant 變數名稱和值
	 * 
	 * @param c
	 *            屬於哪個 class
	 * @param constValue
	 *            數值
	 * @return 變數名稱 ex: ErrorCode.INVALIT_PARAM(12345)
	 */
	public static String getFullNameWithCode(Class<?> c, int constValue) {
		HashMap<Integer, Field> constMap = getConstantCodeMap(c);

		// 找出數值對應的 field
		Field field = constMap.get(constValue);
		if (field == null) {
			return "null";
		}

		return c.getSimpleName() + "." + field.getName() + "(" + constValue + ")";
	}

	/**
	 * 取得對應指定類別的 constant map
	 * 
	 * @param c
	 *            取得對應 constant map 的 class
	 * @return constant map
	 */
	private static HashMap<Integer, Field> getConstantCodeMap(Class<?> c) {
		HashMap<Integer, Field> constMap = null;

		// 找不到 class 就新增一個
		if (!classMap.containsKey(c)) {
			constMap = makeConstantCodeMap(c);
			classMap.put(c, constMap);
		} else { // class 已經存在就拿來查
			constMap = classMap.get(c);
		}

		return constMap;
	}

	/**
	 * 指定一個 class 找出底下所有 int 類型的 field 存成一個 map，可以用 field 的值來反查 field
	 * 
	 * @param c
	 *            指定 class
	 * @return HashMap [Integer, Field]
	 */
	private static HashMap<Integer, Field> makeConstantCodeMap(Class<?> c) {
		HashMap<Integer, Field> constMap = new HashMap<Integer, Field>();

		// 掃一遍 class 下所有的 field
		Field[] fields = c.getFields();
		for (Field field : fields) {
			try {
				// 排除非 int
				if (!field.getType().equals(Integer.TYPE)) {
					continue;
				}

				Integer value = (Integer) field.get(null);
				
				// 發現重複的 int value
				if (constMap.containsKey(value)) {
					Field temp1 = constMap.get(value);
					if (log.isErrorEnabled()) {
						log.error(c.getSimpleName() + " constant id duplicate " + value + " : " + temp1.getName()
								+ " | " + field.getName(), new RuntimeException());
					}
				} else {
					constMap.put(value, field);
				}
			} catch (Exception e) {
				if (log.isErrorEnabled()) {
					log.error(GameUtility.getCurMethodName() + ": fail", e);
					continue;
				}
			}
		}

		return constMap;
	}

	/**
	 * 取得指定 constant code class 裡面項目的 iterator
	 * 
	 * @param c
	 *            指定 class
	 * @return
	 */
	public static Iterator<Entry<Integer, Field>> getIt(Class<?> c) {
		HashMap<Integer, Field> constMap = getConstantCodeMap(c);

		Iterator<Entry<Integer, Field>> it = constMap.entrySet().iterator();

		return it;
	}

	/**
	 * 取得 it 的 next 元素裡面的值
	 * 
	 * @param it
	 *            來自 {@link #getIt(Class)} 的 it
	 * @return
	 */
	public static int getNextValueFromIt(Iterator<Entry<Integer, Field>> it) {
		Field field = it.next().getValue();

		Integer value = null;
		try {
			value = (Integer) field.get(null);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName() + ": fail", e);
				return -1;
			}
		}

		return value;
	}
}
